package com.benmei.ntlive.service;

import com.benmei.ntlive.common.CourseType;
import com.benmei.ntlive.constant.Constants;
import com.benmei.ntlive.dao.*;
import com.benmei.ntlive.dto.*;
import com.benmei.ntlive.dto.ntmsg.cons.Action;
import com.benmei.ntlive.entity.*;
import com.benmei.ntlive.exception.NtClientException;
import com.benmei.ntlive.exception.NtServerException;
import com.benmei.ntlive.utils.JsonUtil;
import com.benmei.ntlive.vo.Room;
import com.benmei.ntlive.vo.Session;
import com.benmei.ntlive.vo.SessionRepository;
import com.benmei.ntlive.vo.User;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by Peter on 2017/9/7.
 */
@Service
public class LiveService {
    private static Logger logger = LoggerFactory.getLogger(LiveService.class);
    @Autowired
    private TeacherDao teacherDao;

    @Autowired
    private MemberDao memberDao;
    @Autowired
    private ClassRoomDao classRoomDao;

    @Autowired
    private ClassRoomEntryLogDao classRoomEntryLogDao;

    @Autowired
    private SessionRepository sessionRepository;

    @Autowired
    private ClassRoomActionDao classRoomActionDao;
    @Resource
    private AgoraUidDao agoraUidDao;

    /**
     * 查询（没有就创建）学生/老师的 agora_uid。声网专用字段：用户 ID。表示该回调报告的是持有该ID的用户的网络质量。
     * 生产环境为正数，测试环境为复数（数字相同）
     *
     * @param role   1学生；2老师
     * @param ext_id 如果role=1则ext_id就是memb_id；如果role=2则ext_id就是tea_id
     * @return
     */
    public synchronized Integer getAgoraUid(Integer role, Integer ext_id) {
        AgoraUid agoraUid = agoraUidDao.find(role, ext_id);
        if (agoraUid == null) {
            agoraUid = new AgoraUid(role, ext_id);
            agoraUidDao.insert(agoraUid);
        }
        return agoraUid.getAgora_uid();
    }


    public Teacher getTeacherByToken(String token) {
        return teacherDao.getByToken(token);
    }

    public Member getMemberByToken(String token) {
        return memberDao.getByToken(token);
    }

    /**
     * 处理业务逻辑
     *
     * @param ctx
     * @param req
     */
    public void process(ChannelHandlerContext ctx, TcpRequest req, String action) throws NtClientException {
        if (Action.TO_PAGE.getName().equalsIgnoreCase(action)) {// 翻译
            toPage(ctx, req, action);
        } else if (Action.DRAWING.getName().equalsIgnoreCase(action)) {// 涂鸦
            drawing(ctx, req, action);
        } else if (Action.ERASER.getName().equalsIgnoreCase(action)) {// 橡皮檫
            eraser(ctx, req, action);
        } else if (Action.MEDIA_CONTROL.getName().equalsIgnoreCase(action)) {// 媒体控制
            mediaControl(ctx, req, action);
        } else if (Action.ALIVE_IN_REQUEST.getName().equalsIgnoreCase(action)) {// 举手
            aliveInRequest(ctx, req, action);
        } else if (Action.ALIVE_OUT_REQUEST.getName().equalsIgnoreCase(action)) {// 取消举手
            aliveOutRequest(ctx, req, action);
        } else if (Action.ACCEPT_ALIVE.getName().equalsIgnoreCase(action)) {// 上麦
            acceptAlive(ctx, req, action);
        } else if (Action.QUIT_ALIVE.getName().equalsIgnoreCase(action)) {// 下麦
            quitAlive(ctx, req, action);
        } else if (Action.STAR.getName().equalsIgnoreCase(action)) {// 发送星星
            star(ctx, req, action);
        } else if (Action.CREATE_SESSION.getName().equalsIgnoreCase(action)) {// 创建session
        } else {
            throw new NtClientException("Invalid action '" + action + "'");
        }
    }

    // 1 涂鸦
    public void drawing(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {
            Map<String, Object> body = req.getBody();
            if (body == null) {
                throw new NtClientException("The parameter 'body' is required", action);
            }

            Object trails = body.get("trails");
            if (trails == null) {
                throw new NtClientException("The parameter 'trails' is required", action);
            }

            // 根据roomId获取房间会话
            Integer roomId = req.getHead().getRoomId();
            String courseType = req.getHead().getCourseType();
            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }

            final ClassRoom classRoom = classRoomDao.findById(roomId);
            if (classRoom == null) {
                throw new NtClientException("ClassRoom do not exists, The roomId=" + roomId, action);
            }
            // 群发消息
            final DrawingResponse drawingResponse = new DrawingResponse(action, trails);
            final List<Session> students = room.getStudents();
            for (final Session student : students) {
                student.getChannel().writeAndFlush(JsonUtil.toJson(drawingResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            logger.info("涂鸦发送成功 to: (" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress());
                        } else {
                            logger.error("涂鸦发送失败 to: (" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress() + "原因为:", future.cause());
                        }
                    }
                });
            }


        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        }

        logger.info("Drawing :: from" + ctx.channel().remoteAddress().toString() + "---->");
    }

    // 2 橡皮檫
    public void eraser(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {

            // 根据roomId获取房间会话
            Integer roomId = req.getHead().getRoomId();
            String courseType = req.getHead().getCourseType();
            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, the roomId=" + roomId, action);
            }

            final ClassRoom classRoom = classRoomDao.findById(roomId);
            if (classRoom == null) {
                throw new NtClientException("ClassRoom do not exists, the roomId=" + roomId, action);
            }

            final EraserResponse response = new EraserResponse(action);
            // 群发消息
            final List<Session> students = room.getStudents();
            for (final Session student : students) {
                student.getChannel().writeAndFlush(JsonUtil.toJson(response) + Constants.delimiter).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            logger.info("橡皮檫发送成功 to:(" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress());
                            ctx.channel().writeAndFlush(JsonUtil.toJson(response) + Constants.delimiter);
                        } else {
                            logger.error("橡皮檫发送失败 to:(" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress() + ", 原因为:", future.cause());
                            ctx.channel().writeAndFlush(new NtClientException("Eraser is error:" + future.cause().getMessage(), action).toJson());
                        }
                    }
                });
            }


        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("系统错误", action).toJson() + Constants.delimiter);
        }

        logger.info("Eraser :: " + ctx.channel().remoteAddress().toString() + "---->" + JsonUtil.toJson(req));
    }

    // 3 翻页
    public void toPage(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        final ClassRoomAction classRoomAction = new ClassRoomAction();
        try {
            Object obj_page = req.getBody().get("page");
            if (obj_page == null) {
                throw new NtClientException("The parameter 'page' is required", action);
            }
            final Integer page;
            try {
                page = Integer.parseInt(obj_page.toString());
            } catch (NumberFormatException e) {
                throw new NtClientException("The parameter 'page' must be number, page=" + obj_page.toString(), action);
            }

            // 根据roomId获取房间会话
            Integer roomId = req.getHead().getRoomId();
            String courseType = req.getHead().getCourseType();
            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }


            final ClassRoom classRoom = classRoomDao.findById(roomId);
            if (classRoom == null) {
                throw new NtClientException("ClassRoom do not exists, The roomId=" + roomId, action);
            }
//            Integer studyPage = memberDao.findStudyPage(classRoom.getMemb_id(), classRoom.getCou_id());
//            studyPage = studyPage == null ? 0 : studyPage;
            classRoomAction.setAction(Action.TO_PAGE.getName());
            classRoomAction.setPage(page);
            classRoomAction.setRoom_id(roomId);
            final ToPageResponse response = new ToPageResponse(action, page);
            // 群发消息
            final List<Session> students = room.getStudents();
            for (final Session student : students) {
                student.getChannel().writeAndFlush(JsonUtil.toJson(response) + Constants.delimiter).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            logger.info("翻页发送成功 to: (" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress());
                            classRoomAction.setResult_code(ClassRoomAction.ResultCode.SUCCESS);
                            ctx.channel().writeAndFlush(JsonUtil.toJson(response) + Constants.delimiter);
                            // TODO 记录上到那里，1v1和1vn，不同的处理
                            Integer lastPageNum = memberDao.findStudyPage(classRoom.getMemb_id(), classRoom.getCou_id());
                            if (lastPageNum == null) {
                                MemberCourse memberCourse = new MemberCourse();
                                memberCourse.setCou_id(classRoom.getCou_id());
                                memberCourse.setMemb_id(classRoom.getMemb_id());
                                Date now = new Date();
                                memberCourse.setEnd_time(now);
                                memberCourse.setStart_time(now);
                                memberCourse.setStudy_page(page);
                                memberDao.insertStudyPage(memberCourse);
                            } else {
                                memberDao.updateStudyPage(classRoom.getMemb_id(), classRoom.getCou_id(), page);
                            }
                        } else {
                            logger.error("翻页发送失败 to: (" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress() + ", 原因为:", future.cause());
                            classRoomAction.setResult_code(ClassRoomAction.ResultCode.ERROR);
                            classRoomAction.setError_msg(future.cause().getMessage());
                            ctx.channel().writeAndFlush(new NtClientException("TO_PAGE is error:" + future.cause().getMessage(), action).toJson() + Constants.delimiter);
                        }
                    }
                });
            }

        } catch (NtClientException e) {
            classRoomAction.setResult_code(ClassRoomAction.ResultCode.ERROR);
            classRoomAction.setError_msg(e.getMessage());
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            classRoomAction.setResult_code(ClassRoomAction.ResultCode.ERROR);
            classRoomAction.setError_msg(e.getMessage());
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        } finally {
            try {
                logger.info(JsonUtil.toJson(classRoomAction));
                classRoomActionDao.insertSelective(classRoomAction);
            } catch (Exception e) {
                logger.error("保存tcp指令到数据库失败：" + e.getMessage(), e);
            }
        }

        logger.info("TO_PAGE :: " + ctx.channel().remoteAddress().toString() + "---->" + JsonUtil.toJson(req));
    }

    // 4 视频控制
    public void mediaControl(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {
            Map<String, Object> body = req.getBody();
            if (body == null) {
                throw new NtClientException("The parameter 'body' is required", action);
            }

            Object cmd = body.get("cmd");
            if (cmd == null) {
                throw new NtClientException("The parameter 'cmd' is required", action);
            }

            // 根据roomId获取房间会话
            Integer roomId = req.getHead().getRoomId();
            String courseType = req.getHead().getCourseType();
            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }

            final ClassRoom classRoom = classRoomDao.findById(roomId);
            if (classRoom == null) {
                throw new NtClientException("ClassRoom do not exists, The roomId=" + roomId, action);
            }
            final MediaControlResponse drawingResponse = new MediaControlResponse(action, cmd);
            // 群发消息
            final List<Session> students = room.getStudents();
            for (final Session student : students) {
                student.getChannel().writeAndFlush(JsonUtil.toJson(drawingResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            logger.info("视频控制指令发送成功 to: (" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress());
                        } else {
                            logger.error("视频控制指令发送失败 to: (" + student.getUser().getId() + ":" + student.getUser().getName() + ")" + student.getChannel().remoteAddress() + "原因为:", future.cause());
                        }
                    }
                });
            }

        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        }

        logger.info("mediaControl :: from" + ctx.channel().remoteAddress().toString() + "---->");
    }

    // 5 举手
    public void aliveInRequest(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {
            Map<String, Object> body = req.getBody();
            if (body == null) {
                throw new NtClientException("The parameter 'body' is required", action);
            }

            // 根据roomId获取房间会话
            Integer roomId = req.getHead().getRoomId();
            String courseType = req.getHead().getCourseType();
            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }

            final ClassRoom classRoom = classRoomDao.findById(roomId);
            if (classRoom == null) {
                throw new NtClientException("ClassRoom do not exists, The roomId=" + roomId, action);
            }

            String endpoint = ctx.channel().remoteAddress().toString();
            Session studentSession = room.getStudentByEndpoint(endpoint);
            if (studentSession == null) {
                throw new NtClientException("ClassRoom(" + classRoom.getRoom_id() + ") do not have this student, The endpoint=" + endpoint);
            }
            User student = studentSession.getUser();
            if (student == null) {
                throw new NtClientException("ClassRoom(" + classRoom.getRoom_id() + ") do not have this student, but have the session, The endpoint=" + endpoint);
            }
            final AliveResponse aliveResponse = new AliveResponse(action, student.getId(), student.getName(), student.getAvatar());

            // 举手队列添加学生
            room.addHandsUpUser(student);
            // 群发举手列表
            sessionRepository.sendHuandsUpListMessageForRoom(room);

        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        }

        logger.info("aliveInRequest :: from" + ctx.channel().remoteAddress().toString() + "---->");
    }

    // 6 取消举手
    public void aliveOutRequest(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {
            Map<String, Object> body = req.getBody();
            if (body == null) {
                throw new NtClientException("The parameter 'body' is required", action);
            }

            // 根据roomId获取房间会话
            final Integer roomId = req.getHead().getRoomId();
            final String courseType = req.getHead().getCourseType();
            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }

            String endpoint = ctx.channel().remoteAddress().toString();
            Session studentSession = room.getStudentByEndpoint(endpoint);
            if (studentSession == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, The endpoint=" + endpoint);
            }
            User student = studentSession.getUser();
            if (student == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, but have the session, The endpoint=" + endpoint);
            }
            final AliveResponse aliveResponse = new AliveResponse(action, student.getId(), student.getName(), student.getAvatar());
            // 群发举手列表
            room.removeHandsUpUser(student);
            sessionRepository.sendHuandsUpListMessageForRoom(room);
        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        }

        logger.info("aliveOutRequest :: from" + ctx.channel().remoteAddress().toString() + "---->");
    }

    // 7 上麦
    public void acceptAlive(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {
            Map<String, Object> body = req.getBody();
            if (body == null) {
                throw new NtClientException("The parameter 'body' is required", action);
            }

            // 根据roomId获取房间会话
            final Integer roomId = req.getHead().getRoomId();
            final String courseType = req.getHead().getCourseType();

            Object obj_membId = req.getBody().get("membId");
            if (obj_membId == null) {
                throw new NtClientException("The parameter 'membId' is required", action);
            }
            final Integer membId;
            try {
                membId = Integer.parseInt(obj_membId.toString());
            } catch (NumberFormatException e) {
                throw new NtClientException("The parameter 'membId' must be number, obj_membId=" + obj_membId.toString(), action);
            }

            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }

            Session studentSession = room.getStudentByMembId(membId);
            if (studentSession == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, The membId=" + membId);
            }
            User student = studentSession.getUser();
            if (student == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, but have the session, The membId=" + membId);
            }
            final AliveResponse aliveResponse = new AliveResponse(action, student.getId(), student.getName(), student.getAvatar());
            // 群发消息 to 所有学生 (to all students)
            final List<Session> students = room.getStudents();
            for (final Session stu : students) {
                stu.getChannel().writeAndFlush(JsonUtil.toJson(aliveResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            logger.info("上麦指令发送成功（教室：" + courseType + "_" + roomId + "） to: Student(" + stu.getUser().getId() + ":" + stu.getUser().getName() + ")" + stu.getChannel().remoteAddress());
                        } else {
                            logger.error("上麦指令发送失败（教室：" + courseType + "_" + roomId + "） to: Student(" + stu.getUser().getId() + ":" + stu.getUser().getName() + ")" + stu.getChannel().remoteAddress() + "原因为:", future.cause());
                        }
                    }
                });
            }

            ctx.channel().writeAndFlush(JsonUtil.toJson(aliveResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        logger.info("上麦指令发送成功（教室：" + courseType + "_" + roomId + "） to: Teacher");
                    } else {
                        logger.error("上麦指令发送失败（教室：" + courseType + "_" + roomId + "） to: Teacher");
                    }
                }
            });


            room.removeHandsUpUser(student);// 举手队列移除学生
            sessionRepository.sendHuandsUpListMessageForRoom(room);// 群发举手列表

        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        }

        logger.info("acceptAlive :: from" + ctx.channel().remoteAddress().toString() + "---->");
    }

    // 8 下麦
    public void quitAlive(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {
            Map<String, Object> body = req.getBody();
            if (body == null) {
                throw new NtClientException("The parameter 'body' is required", action);
            }

            // 根据roomId获取房间会话
            final Integer roomId = req.getHead().getRoomId();
            final String courseType = req.getHead().getCourseType();
            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }

            Object obj_membId = req.getBody().get("membId");
            if (obj_membId == null) {
                throw new NtClientException("The parameter 'membId' is required", action);
            }
            final Integer membId;
            try {
                membId = Integer.parseInt(obj_membId.toString());
            } catch (NumberFormatException e) {
                throw new NtClientException("The parameter 'membId' must be number, obj_membId=" + obj_membId.toString(), action);
            }

            Session studentSession = room.getStudentByMembId(membId);
            if (studentSession == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, The membId=" + membId);
            }
            User student = studentSession.getUser();
            if (student == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, but have the session, The membId=" + membId);
            }
            final AliveResponse aliveResponse = new AliveResponse(action, student.getId(), student.getName(), student.getAvatar());
            // 群发消息 (to all students)
            final List<Session> students = room.getStudents();
            for (final Session stu : students) {
                stu.getChannel().writeAndFlush(JsonUtil.toJson(aliveResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            logger.info("下麦指令发送成功（教室：" + courseType + "_" + roomId + "） to: Student(" + stu.getUser().getId() + ":" + stu.getUser().getName() + ")" + stu.getChannel().remoteAddress());
                        } else {
                            logger.error("下麦指令发送失败（教室：" + courseType + "_" + roomId + "） to: Student(" + stu.getUser().getId() + ":" + stu.getUser().getName() + ")" + stu.getChannel().remoteAddress() + "原因为:", future.cause());
                        }
                    }
                });
            }

            // 下麦指令发给老师
            ctx.channel().writeAndFlush(JsonUtil.toJson(aliveResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        logger.info("下麦指令发送成功（教室：" + courseType + "_" + roomId + "） to: Teacher");
                    } else {
                        logger.error("下麦指令发送失败（教室：" + courseType + "_" + roomId + "） to: Teacher 原因为:", future.cause());
                    }
                }
            });


        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        }

        logger.info("quitAlive :: from" + ctx.channel().remoteAddress().toString() + "---->");
    }

    // 9 老师给学生发送一个星星（点赞）
    public void star(final ChannelHandlerContext ctx, TcpRequest req, final String action) {
        try {
            Map<String, Object> body = req.getBody();
            if (body == null) {
                throw new NtClientException("The parameter 'body' is required", action);
            }

            // 根据roomId获取房间会话
            final Integer roomId = req.getHead().getRoomId();
            final String courseType = req.getHead().getCourseType();
            if (!CourseType.c_1v1.getName().equalsIgnoreCase(courseType)) {
                throw new NtClientException("CourseType error,in star action that must be '1v1',but this is '" + courseType + "'", action);
            }

            Object obj_membId = req.getBody().get("membId");
            if (obj_membId == null) {
                throw new NtClientException("The parameter 'membId' is required", action);
            }
            final Integer membId;
            try {
                membId = Integer.parseInt(obj_membId.toString());
            } catch (NumberFormatException e) {
                throw new NtClientException("The parameter 'membId' must be number, obj_membId=" + obj_membId.toString(), action);
            }

            Room room = sessionRepository.getRoom(courseType, roomId);
            if (room == null) {
                throw new NtClientException("Room session do not exists, The roomId=" + roomId, action);
            }

            Session studentSession = room.getStudentByMembId(membId);
            if (studentSession == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, The membId=" + membId);
            }
            User student = studentSession.getUser();
            if (student == null) {
                throw new NtClientException("ClassRoom(" + courseType + "_" + roomId + ") do not have this student, but have the session, The membId=" + membId);
            }
            // 查询学生获取的星星数量
            Integer star_size = classRoomDao.findStarByRoomId(roomId);
            if (star_size == null) {
                star_size = 0;
            }
            final Integer starSize = star_size;
            final StarResponse starResponse = new StarResponse(action, starSize + 1);
            // 发送星星给学生
                    studentSession.getChannel().writeAndFlush(JsonUtil.toJson(starResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                        @Override
                        public void operationComplete(ChannelFuture future) throws Exception {
                            if (future.isSuccess()) {
                                logger.info("发送星星给学生成功（教室：" + courseType + "_" + roomId + "） starSize=" + starSize);

                                classRoomDao.starSizePlusOne(roomId);// 数据库星星数量+1

                                // 告诉老师星星发送成功
                                ctx.channel().writeAndFlush(JsonUtil.toJson(starResponse) + Constants.delimiter).addListener(new ChannelFutureListener() {
                                    @Override
                                    public void operationComplete(ChannelFuture future) throws Exception {
                                        if (future.isSuccess()) {
                                            logger.info("发送星星给老师成功（教室：" + courseType + "_" + roomId + "）starSize=" + starSize);
                                        } else {
                                            logger.error("发送星星给老师失败（教室：" + courseType + "_" + roomId + "）starSize=" + starSize);
                                        }
                                    }
                                });
                            } else {
                                logger.error("发送星星给学生失败（教室：" + courseType + "_" + roomId + "） starSize=" + starSize);
                            }
                }
            });


            room.removeHandsUpUser(student);// 举手队列移除学生
            sessionRepository.sendHuandsUpListMessageForRoom(room);// 群发举手列表

        } catch (NtClientException e) {
            ctx.channel().writeAndFlush(e.toJson() + Constants.delimiter);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ctx.channel().writeAndFlush(new NtServerException("The parameter 'page' is required", action).toJson() + Constants.delimiter);
        }

        logger.info("acceptAlive :: from" + ctx.channel().remoteAddress().toString() + "---->");
    }

    public void roomLog(ClassRoomEntryLog roomLog) {
        classRoomEntryLogDao.insertSelective(roomLog);
    }

    public ClassRoom findRoomById(Integer roomId) {
        return classRoomDao.findById(roomId);
    }

    public McCourseSchedule findMcCourseRoomById(Integer roomId) {
        return classRoomDao.findMcCourseRoomById(roomId);
    }

    public Integer findStarByRoomId(Integer roomId) {
        return classRoomDao.findStarByRoomId(roomId);
    }
}
